﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;

namespace Ndex.Core
{
    public interface IPagination
    {
        string OrderBy { get; set; }
        bool OrderAscending { get; set; }
        int OrderNumber { get; set; }
        bool TakeAll { get; set; }
        bool HasPaging { get; set; }
        int PageSize { get; set; }
        int Current { get; set; }
        int NoPages { get; set; }
        int NoItems { get; set; }
    }

    public static class IPaginationExt
    {
        public static int GetSkip(this IPagination paging)
        {
            return Math.Max((paging.Current - 1) * paging.PageSize, 0); 
        }

        public static IQueryable<T> Paging<T>(this IQueryable<T> query, IPagination paging)
        {
            if (paging == null)
                return query;

            paging.NoItems = query.Count();
            query = query.Sort(paging);
            paging.NoPages = 1;
            if (!paging.IsValid() || paging.NoItems <= paging.PageSize || !paging.HasPaging)
                return query;

            paging.NoPages = paging.NoItems / paging.PageSize;
            if (paging.NoItems % paging.PageSize != 0)
                paging.NoPages++;
            var skip = paging.GetSkip();
            return paging.TakeAll ? query.Skip(skip) : query.Skip(skip).Take(paging.PageSize);
        }

        public static IEnumerable<ValidationModel> Validate(this IPagination paging)
        {
            var result = new List<ValidationModel>();
            if (paging.HasPaging)
            {
                if (paging.PageSize <= 0)
                    result.Add("Page size must be larger than zero", "PageSize");
            }
            return result;
        }

        public static bool IsValid(this IPagination paging)
        {
            return !paging.Validate().Any();
        }

        public static string ToStringEx(this IPagination order)
        {
            order.OrderBy = order.OrderBy ?? string.Empty;
            if (order.OrderBy == string.Empty)
                order.OrderBy = "Id";
            return string.Format("{0} {1}", order.OrderBy, order.GetDirection());
        }

        public static string GetDirection(this IPagination order)
        {
            return order.OrderAscending ? "ASC" : "DESC";
        }

        public static IQueryable<T> Sort<T>(this IQueryable<T> query, IPagination order)
        {
            if(order.ToStringEx() != string.Empty)
                query = query.OrderBy(order.ToStringEx());
            return query;
        }

        public static List<T> SortExt<T>(this List<T> query, IPagination order)
        {
            return query.AsQueryable().OrderBy(order.ToStringEx()).ToList();
        }

        public static List<T> Paging<T>(this List<T> query, IPagination paging)
        {
            return query.AsQueryable().Paging(paging).ToList();
        }
    }
}
